package com.wyman.factory.support;

import com.wyman.BeanException;
import com.wyman.PropertyValue;
import com.wyman.PropertyValues;
import com.wyman.factory.config.AutowireCapableBeanFactory;
import com.wyman.factory.config.BeanDefinition;
import com.wyman.factory.config.BeanPostProcessor;
import com.wyman.factory.config.BeanReference;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

/**
 * @Author 李伟民
 * @Description DateTime 2024/11/25 01:43
 */

//6 12.11 新增对AutowireCapableBeanFactory接口中定义的真正执行bean初始化前后方法的实现
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {

    private InstantiationStrategy instantiationStrategy = new SimpleInstantiationStrategy();

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition,Object[] args) throws BeanException {

        Object bean;
        //3. 修改真正创建bean的动作
        //bean =  beanDefinition.getBeanClass().newInstance();
        bean = createBeanInstance(beanDefinition,beanName,args);

        //4. 增加给bean的属性赋值
        applyPropertyValues(beanName,bean,beanDefinition);

        //12.11 6. 真正将bean实例添加到容器之前进行处理 包括前置处理 初始化操作 后置处理
        bean = initializeBean(beanName,bean,beanDefinition);

        //负责管理实例化的bean
        addSingleton(beanName,bean);
        return bean;
    }

    //4.新增
    private void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {

        PropertyValues propertyValues = beanDefinition.getPropertyValues();
        Class<?> clazz = beanDefinition.getBeanClass();

        try {
            for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {

                Object value = propertyValue.getValue();
                Field field = clazz.getDeclaredField(propertyValue.getName());
                //用于获取递归拿到的bean对象值
                Object recBean = null;

                //如果属性也是对象 递归实例化
                if(value instanceof BeanReference){
                    recBean = getBean(((BeanReference) value).getBeanName());
                    //使用反射设置属性值 不用工具类
                    field.setAccessible(true);
                    field.set(bean,recBean);

                }
                //如果是基本类型 则直接用value设置值
                else {
                    field.setAccessible(true);
                    field.set(bean,value);
                }

            }
        }
        catch (NoSuchFieldException | IllegalAccessException  e) {
            throw new BeanException("设置Bean属性值失败！"+beanName);
        }
    }

    //根据args找到合适的构造器 调用instantiationStrategy中的实例化方法创建bean
    private Object createBeanInstance(BeanDefinition beanDefinition, String beanName, Object[] args) {

        Object bean = null;

        //空参情况
        if(args==null){
           return instantiationStrategy.instantiate(beanDefinition,beanName,null,null);
        }

        //带参情况
        Class<?> clazz = beanDefinition.getBeanClass();
        for(Constructor ctor:clazz.getDeclaredConstructors()){

           if(ctor.getParameterTypes().length == args.length){
             bean =  getInstantiationStrategy().instantiate(beanDefinition, beanName, ctor, args);
           }
        }

        return bean;
    }

    public InstantiationStrategy getInstantiationStrategy(){
        return this.instantiationStrategy;
    }

    public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy){
        this.instantiationStrategy = instantiationStrategy;
    }


    private Object initializeBean(String beanName,Object bean,BeanDefinition beanDefinition){

        //前置处理 传beanName和bean对象 对应接口AutowireCapableBeanFactory中的 before方法
        Object wrapperBean = applyBeanPostProcessorsBeforeInitialization(bean,beanName);
        //初始处理 传beanName和bean对象和BeanDefinition
        invokeInitMethods(beanName,wrapperBean,beanDefinition);
        //后置处理 传beanName和bean对象 对应接口AutowireCapableBeanFactory中的 after方法
        wrapperBean = applyBeanPostProcessorsAfterInitialization(wrapperBean,beanName);
        return wrapperBean;
    }

    //实现接口 before方法 存储处理器的列表在父类中 父类还提供了获取列表方法
    @Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean,String beanName) throws BeanException{
        Object res = existingBean;
        for(BeanPostProcessor beanPostProcessor:getBeanPostProcessors()) {
            Object cur = beanPostProcessor.postProcessBeforeInitialization(res, beanName);
            if (cur == null) {
                return res;
            }
            res = cur;
        }
        return res;
    }

    //实现接口 after方法
    @Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeanException {
        Object res = existingBean;
        for(BeanPostProcessor beanPostProcessor:getBeanPostProcessors()){
            Object cur = beanPostProcessor.postProcessAfterInitialization(res,beanName);
            if(cur==null){
                return res;
            }
            res = cur;
        }
        return res;
    }

    //初始处理 目前没有接口定义
    public void invokeInitMethods(String beanName,Object wrapperBean,BeanDefinition beanDefinition){

    }
}
